package org.qpcr.supports.official;

import org.qpcr.core.metadata.DataType;
import org.qpcr.core.metadata.DataTypeCodec;
import org.qpcr.supports.official.types.TyLinksArrayCodec;
import org.qpcr.supports.official.types.TyLinksBooleanCodec;
import org.qpcr.supports.official.types.TyLinksDateCodec;
import org.qpcr.supports.official.types.TyLinksDoubleCodec;
import org.qpcr.supports.official.types.TyLinksEnumCodec;
import org.qpcr.supports.official.types.TyLinksFileCodec;
import org.qpcr.supports.official.types.TyLinksFloatCodec;
import org.qpcr.supports.official.types.TyLinksGeoPointCodec;
import org.qpcr.supports.official.types.TyLinksGeoShapeCodec;
import org.qpcr.supports.official.types.TyLinksIntCodec;
import org.qpcr.supports.official.types.TyLinksLongCodec;
import org.qpcr.supports.official.types.TyLinksObjectCodec;
import org.qpcr.supports.official.types.TyLinksPasswordCodec;
import org.qpcr.supports.official.types.TyLinksShortCodec;
import org.qpcr.supports.official.types.TyLinksStringCodec;
import org.qpcr.supports.official.types.TyLinksUserCodec;

import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

public class TyLinksDataTypeCodecs {

    private static final Map<String, DataTypeCodec<? extends DataType>> codecMap = new HashMap<>();

    static {
        register(new TyLinksArrayCodec());
        register(new TyLinksBooleanCodec());
        register(new TyLinksDateCodec());
        register(new TyLinksDoubleCodec());
        register(new TyLinksEnumCodec());
        register(new TyLinksFloatCodec());
        register(new TyLinksGeoPointCodec());
        register(new TyLinksIntCodec());
        register(new TyLinksLongCodec());
        register(new TyLinksObjectCodec());
        register(new TyLinksStringCodec());
        register(new TyLinksPasswordCodec());
        register(new TyLinksFileCodec());
        register(new TyLinksGeoShapeCodec());
        register(new TyLinksUserCodec());
        register(new TyLinksShortCodec());
    }

    public static void register(DataTypeCodec<? extends DataType> codec) {
        codecMap.put(codec.getTypeId(), codec);
    }

    @SuppressWarnings("all")
    public static Optional<DataTypeCodec<DataType>> getCodec(String typeId) {

        return Optional.ofNullable((DataTypeCodec) codecMap.get(typeId));
    }

    public static DataType decode(DataType type, Map<String, Object> config) {
        if (type == null) {
            return null;
        }
        return getCodec(type.getId())
                .map(codec -> codec.decode(type, config))
                .orElse(type);
    }

    public static Optional<Map<String, Object>> encode(DataType type) {
        if (type == null) {
            return Optional.empty();
        }
        return getCodec(type.getId())
                .map(codec -> codec.encode(type));
    }
}
